package zk.tool.handler;

import javafx.application.Platform;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import zk.tool.ZKClient;
import zk.tool.component.NodeItem;
import zk.tool.model.TreeItemData;
import zk.tool.ui.AppController;
import zk.tool.ui.UIManager;
import zk.tool.util.TreeCommon;

import java.util.List;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

public class TreeItemExpandHandler implements EventHandler<TreeItem.TreeModificationEvent<TreeItemData>> {
    private static final Logger log = LoggerFactory.getLogger(TreeItemExpandHandler.class);

    /**
     * 异步加载数据专用线程池
     */
    private static final ThreadPoolExecutor POOL_EXECUTOR = new ThreadPoolExecutor(
            0, 3, 2, TimeUnit.SECONDS, new LinkedBlockingDeque<>(),
            r -> new Thread(r, "tree_view_item_load_thread-" + System.currentTimeMillis())
    );

    private ZKClient client;

    public TreeItemExpandHandler(ZKClient client) {
        this.client = client;
    }

    @Override
    public void handle(TreeItem.TreeModificationEvent<TreeItemData> event) {
        log.info("event: " + event.getEventType().toString());
        TreeItem<TreeItemData> treeItem = event.getTreeItem();
        if (treeItem == null) {
            return;
        }
        TreeItemData itemData = treeItem.getValue();
        if (itemData == null) {
            return;
        }
        AppController controller = UIManager.getInstance().getController(AppController.class);
        if (controller != null) {
            TreeView<TreeItemData> treeView = controller.getTreeView();
            if (treeView != null) {
                treeView.getSelectionModel().select(treeItem);
            }
        }

        POOL_EXECUTOR.execute(() -> {
            if (itemData.isChildrenLoaded()) {
                log.info("children is loaded: " + itemData.getPath());
                return;
            }
            synchronized (treeItem) {
                if (itemData.isChildrenLoaded()) {
                    log.info("children is loaded: " + itemData.getPath());
                    return;
                }
                ObservableList<TreeItem<TreeItemData>> children = treeItem.getChildren();
                Platform.runLater(() -> {
                    children.clear();
                    children.add(new NodeItem(new TreeItemData("", "加载中...")));
                });
                String path = itemData.getPath();
                try {
                    List<TreeItem<TreeItemData>> items = TreeCommon.loadChildren(client, path);
                    Platform.runLater(() -> {
                        itemData.setChildrenLoaded(true);
                        children.clear();
                        children.addAll(items);
                    });
                } catch (Exception e) {
                    log.error("load children error: ", e);
                }
            }
        });
    }

}
